package am.ik.categolj2.api.error;
import am.ik.categolj2.core.logger.LogManager;
import am.ik.categolj2.core.web.RemoteAddresses;
import am.ik.categolj2.core.web.UserAgents;
import org.slf4j.Logger;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.dao.PessimisticLockingFailureException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.Authentication;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import org.terasoluna.gfw.common.exception.BusinessException;
import org.terasoluna.gfw.common.exception.ExceptionCodeResolver;
import org.terasoluna.gfw.common.exception.ResourceNotFoundException;
import org.terasoluna.gfw.common.exception.ResultMessagesNotificationException;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
@ControllerAdvice(basePackages = "am.ik.categolj2.api")
public class ApiGlobalExceptionHandler extends ResponseEntityExceptionHandler {
private static final Logger logger = LogManager.getLogger();
@Inject
ApiErrorCreator apiErrorCreator;
@Inject
ExceptionCodeResolver exceptionCodeResolver;
@Override
protected ResponseEntity<Object> handleExceptionInternal(Exception ex,
Object body, HttpHeaders headers, HttpStatus status,
WebRequest request) {
final Object apiError;
if (body == null) {
String errorCode = exceptionCodeResolver.resolveExceptionCode(ex);
apiError = apiErrorCreator.createApiError(request, errorCode, ex
.getLocalizedMessage());
} else {
apiError = body;
}
return new ResponseEntity<>(apiError, headers, status);
}
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(
MethodArgumentNotValidException ex, HttpHeaders headers,
HttpStatus status, WebRequest request) {
return handleBindingResult(ex, ex.getBindingResult(), headers, status,
request);
}
@Override
protected ResponseEntity<Object> handleBindException(BindException ex,
HttpHeaders headers, HttpStatus status, WebRequest request) {
return handleBindingResult(ex, ex.getBindingResult(), headers, status,
request);
}
private ResponseEntity<Object> handleBindingResult(Exception ex,
BindingResult bindingResult, HttpHeaders headers,
HttpStatus status, WebRequest request) {
String errorCode = exceptionCodeResolver.resolveExceptionCode(ex);
ApiError apiError = apiErrorCreator.createBindingResultApiError(
request, errorCode, bindingResult, ex.getMessage());
return handleExceptionInternal(ex, apiError, headers, status, request);
}
@Override
protected ResponseEntity<Object> handleHttpMessageNotReadable(
HttpMessageNotReadableException ex, HttpHeaders headers,
HttpStatus status, WebRequest request) {
if (ex.getCause() instanceof Exception) {
return handleExceptionInternal((Exception) ex.getCause(), null,
headers, status, request);
} else {
return handleExceptionInternal(ex, null, headers, status, request);
}
}
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<Object> handleResourceNotFoundException(
ResourceNotFoundException ex, WebRequest request) {
return handleResultMessagesNotificationException(ex, null,
HttpStatus.NOT_FOUND, request);
}
@ExceptionHandler(BusinessException.class)
public ResponseEntity<Object> handleBusinessException(BusinessException ex,
WebRequest request) {
return handleResultMessagesNotificationException(ex, null,
HttpStatus.CONFLICT, request);
}
private ResponseEntity<Object> handleResultMessagesNotificationException(
ResultMessagesNotificationException ex, HttpHeaders headers,
HttpStatus status, WebRequest request) {
String errorCode = exceptionCodeResolver.resolveExceptionCode(ex);
ApiError apiError = apiErrorCreator.createResultMessagesApiError(
request, errorCode, ex.getResultMessages(), ex.getMessage());
return handleExceptionInternal(ex, apiError, headers, status, request);
}
@ExceptionHandler({OptimisticLockingFailureException.class,
PessimisticLockingFailureException.class})
public ResponseEntity<Object> handleLockingFailureException(Exception ex,
WebRequest request) {
return handleExceptionInternal(ex, null, null, HttpStatus.CONFLICT,
request);
}
@ExceptionHandler(AccessDeniedException.class)
public ResponseEntity<Object> handleAccessDeniedException(Exception ex,
WebRequest request, HttpServletRequest servletRequest, Authentication authentication) {
if (logger.isWarnEnabled()) {
logger.warn("Access denied! method={},uri={},query={},principal={},remote={},user-agent={}",
servletRequest.getMethod(),
servletRequest.getRequestURI(),
servletRequest.getQueryString(),
authentication == null ? "@@@@" : authentication.getName(),
RemoteAddresses.getRemoteAddress(servletRequest),
UserAgents.getUserAgent(servletRequest));
}
return handleExceptionInternal(ex, null, null, HttpStatus.FORBIDDEN, request);
}
@ExceptionHandler(MultipartException.class)
public ResponseEntity<Object> handleMultipartException(Exception ex,
WebRequest request) {
return handleExceptionInternal(ex, null, null, HttpStatus.BAD_REQUEST, request);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<Object> handleSystemError(Exception ex,
WebRequest request) {
return handleExceptionInternal(ex, null, null,
HttpStatus.INTERNAL_SERVER_ERROR, request);
}
}